#!/usr/bin/env python 
# -*- coding:utf-8 -*-
import json
import re
import time

import browsermobproxy
from selenium import webdriver
from selenium.webdriver import ChromeOptions, FirefoxProfile
from selenium.webdriver.support.wait import WebDriverWait

from app.db.mongo_db import Mongo_db
from app.douyin import mongo_db_host, mongo_db_port
from app.douyin.entity.douyin_info import douyin_info

"""
Required:
    pip install selenium
    pip install browsermob-proxy
    pip install pymongo
"""

# mongo
douyin_db = Mongo_db(mongo_db_host, mongo_db_port).get_db('douyin')
douyin_info_coll = douyin_db['douyinInfo']
codes = {
    "xe603": "0", "xe60d": "0", "xe616": "0",
    "xe602": "1", "xe60e": "1", "xe618": "1",
    "xe605": "2", "xe610": "2", "xe617": "2",
    "xe604": "3", "xe611": "3", "xe61a": "3",
    "xe606": "4", "xe60c": "4", "xe619": "4",
    "xe607": "5", "xe60f": "5", "xe61b": "5",
    "xe608": "6", "xe612": "6", "xe61f": "6",
    "xe60a": "7", "xe613": "7", "xe61c": "7",
    "xe60b": "8", "xe614": "8", "xe61d": "8",
    "xe609": "9", "xe615": "9", "xe61e": "9"
}


class proxy_test(object):

    def __init__(self, type='chrome'):
        print("程序初始化")
        self._init_proxy()
        if type == 'firefox':
            self._init_firefox()
        else:
            self._init_chrome()

    def _init_proxy(self):
        print("初始化代理服务")
        # 代理服务
        path = r"/Users/kunda-liang/Downloads/browsermob-proxy-2.1.4/bin/browsermob-proxy"
        # 初始化一个代理Manager服务，并监听8080端口
        self.server = browsermobproxy.Server(path=path, options={'port': 8180})
        # 启动代理Manager服务
        self.server.start()
        # 向代理Manager服务申请一个代理服务
        self.proxy = self.server.create_proxy()
        # 向已有代理Manager服务申请一个代理服务
        # self.proxy = browsermobproxy.Client('http://localhost:8080')
        print("代理接口 port = %s " % self.proxy.port)

    def _init_chrome(self):
        print("初始化chrome")
        if not self.server or not self.proxy:
            self._init_proxy()

        # webdriver
        options = ChromeOptions()
        options.add_argument('--ignore-certificate-errors')
        # options.add_argument('--proxy-server={0}'.format(self.proxy.proxy))
        options.add_argument('--proxy-server={host}:{port}'.format(host="localhost", port=self.proxy.port))
        options.add_argument('--disable-gpu')
        options.add_argument('--disable-cache')
        # options.add_argument('--headless')
        options.headless = True
        options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})  # 禁用加载图片
        options.add_experimental_option('excludeSwitches', ['enable-automation'])
        self.driver = webdriver.Chrome(chrome_options=options)
        self.wait = WebDriverWait(self.driver, 10)

    def _init_firefox(self):
        print("初始化firefox浏览器")

        profile = FirefoxProfile()
        profile.set_preference('permissions.default.image', 2)  # 禁用加载图片

        # 方案1 失败
        # self.driver = webdriver.Firefox(firefox_profile=profile, proxy=self.proxy.selenium_proxy())

        # 方案2 只有http，
        # 激活手动代理配置（对应着在 profile（配置文件）中设置首选项）
        profile.set_preference("network.proxy.type", 1)
        # ip及其端口号配置为 http 协议代理
        profile.set_preference("network.proxy.http", "localhost")
        profile.set_preference("network.proxy.http_port", self.proxy.port)
        # 有https
        profile.set_preference('network.proxy.ssl', "localhost")
        profile.set_preference('network.proxy.ssl_port', self.proxy.port)
        # 所有协议共用一种 ip 及端口，如果单独配置，不必设置该项，因为其默认为 False
        profile.set_preference("network.proxy.share_proxy_settings", True)
        self.driver = webdriver.Firefox(firefox_profile=profile)

        # self.driver.get("http://www.baidu.com")
        # time.sleep(3)
        # self.driver.quit()

    def _open_proxy(self, ref, options=None):
        """
        打开代理监控
        :param ref:
        :param options:
        :return:
        """
        if options is None:
            options = {'captureContent': True, 'captureHeaders': True}
        print("设置代理")
        self.proxy.new_har(ref, options=options)

    def _open_url(self, local_url):
        print("打开网页")
        self.driver.delete_all_cookies()
        self.driver.get(local_url)

    def _click_works(self, retry=3):
        # time.sleep(1)
        print("点击作品按钮")
        try:
            element = self.driver.find_element_by_class_name("user-tab")
            self.driver.execute_script("arguments[0].click();", element)
        except:
            print("点击作品按钮异常，刷新页面")
            time.sleep(1)
            self.driver.refresh()
            if retry > 0:
                retry -= 1
                self._click_works(retry)
            else:
                print("点击作品按钮失败，跳过该步骤")

    def _get_info(self, local_url, retry=3):
        """
        h5页面数据解析
        :param local_url: 请求的url
        :return:
        """
        # uid
        uid = re.search(r'/[0-9]*$', local_url).group()
        if uid:
            uid = uid[1:]
        else:
            uid = ''
        print("uid = {}".format(uid))

        try:
            # 昵称
            nickname_ele = self.driver.find_element_by_class_name('nickname')
            print("nickname = {}".format(nickname_ele.text))

            # 抖音id
            shortid_ele = self.driver.find_element_by_xpath("//p[@class='shortid']")
            shortid_text = re.sub(r'(抖音ID(：|:)?|\s*)', '', shortid_ele.text)
            d_id = ''
            for i in shortid_text:
                if i > u'\u9fa5':
                    d_id += _code_replace(i)
                else:
                    d_id += i
            print("d_id = {}".format(d_id))

            # 关注
            focus_ele = self.driver.find_element_by_xpath("//span[@class='focus block']/span")
            focus_num, focus_unit = _get_num(focus_ele.text)
            # print("focus_num = {}, focus_unit = {}".format(focus_num, focus_unit))

            # 粉丝
            follower_ele = self.driver.find_element_by_xpath("//span[@class='follower block']/span")
            follower_num, follower_unit = _get_num(follower_ele.text)
            # print("follower_num = {}, follower_unit = {}".format(follower_num, follower_unit))

            # 赞
            liked_ele = self.driver.find_element_by_xpath("//span[@class='liked-num block']/span")
            liked_num, liked_unit = _get_num(liked_ele.text)
            # print("liked_num = {}, liked_unit = {}".format(liked_num, liked_unit))

            # 作品数
            works_ele = self.driver.find_element_by_class_name('user-tab').find_element_by_class_name("num")
            works_num, works_unit = _get_num(works_ele.text)
            # print("works_num = {}, works_unit = {}".format(works_num, works_unit))

            # 喜欢数
            liked2_ele = self.driver.find_element_by_xpath("//div[@class='like-tab tab get-list']/span")
            liked2_num, liked2_unit = _get_num(liked2_ele.text)
            # print("liked2_num = {}, liked2_unit = {}".format(liked2_num, liked2_unit))

            di = douyin_info(
                uid=uid,
                douId=d_id,  # string
                name=nickname_ele.text,
                focus=int(focus_num),
                focusUnit=focus_unit if focus_unit else None,
                follower=int(follower_num),
                followerUnit=follower_unit if follower_unit else None,
                liked=int(liked_num),
                likedUnit=liked_unit if liked_unit else None,
                works=int(works_num),
                liked2=int(liked2_num)
            )
            return di
        except:
            print("h5页面数据解析异常，刷新页面")
            time.sleep(1)
            self.driver.refresh()
            if retry > 0:
                retry -= 1
                return self._get_info(local_url, retry)
            else:
                print("h5页面数据解析失败，跳过该步骤")
                return None

    def _get_works(self, match_url):
        """
        取出作品数据
        :param match_url: 作品数据匹配接口
        :return:
        """
        # time.sleep(10)
        print("检查 response 数据")
        # 取出数据
        result = self.proxy.har

        # 匹配response
        resp_content = None
        try:
            for entry in result['log']['entries']:
                req_url = entry['request']['url']
                res = re.match(match_url, req_url)
                if res:
                    resp_content = entry["response"]['content']["text"]
                    # print("resp_content %s" % resp_content)
                    resp_content = json.loads(resp_content, encoding='utf-8')
                    break
        except Exception:
            print("匹配resp_content异常: ")

        # 取出作品数据
        if resp_content:
            aweme_list = resp_content.get('aweme_list')
            if aweme_list:
                print("存在 aweme_list")
                return aweme_list
            else:
                print("不存在 aweme_list")
        else:
            print("不存在 resp_content")

        return None

    def _save_douyin_info(self, entity):
        print("保存数据到mongo")
        try:
            if entity and entity.get_json():
                douyin_info_coll.update_one(
                    {'uid': entity.uid},
                    {'$set': json.loads(entity.get_json())},
                    upsert=True
                )
        except Exception:
            print("保存mongo产生异常")

    def main(self, local_url):
        """
        入口
        :param local_url:
        :return:
        """
        print("开始业务")
        try:
            if not self.driver:
                self._init_chrome()

            # 代理监控
            self._open_proxy(local_url)
            # 打开网页
            self._open_url(local_url)
            # 打开作品标签
            self._click_works()
            # 获取页面数据
            douyin_info = self._get_info(local_url)
            if douyin_info:
                # 获取接口数据
                works_list = self._get_works('https://www.iesdouyin.com/web/api/v2/aweme/post/')
                if works_list:
                    douyin_info.worksList = works_list

                # self._save_douyin_info(douyin_info)
            else:
                print("没有获取到用户基本信息，跳过该条记录")
        except Exception:
            print('main 异常')

    def quit(self):
        print("程序退出")
        try:
            if self.proxy:
                self.proxy.wait_for_traffic_to_stop(1000, 6000)
                self.proxy.close()
            if self.server:
                self.server.process.terminate()
                self.server.stop()
            if self.driver:
                self.driver.close()
                self.driver.quit()
        except OSError:
            pass


def _get_num(content_text):
    result_str = ''
    unit_str = content_text[-1:]
    unit_str = unit_str if unit_str.isalpha() else ''
    # 过滤其它字符串
    content_text = re.sub(r'([a-z]*|\.*|\s*)', '', content_text)
    for i in content_text:
        result_str += _code_replace(i)
    return result_str, unit_str


def _code_replace(id_string):
    # 转unicode
    result = ''
    result.encode()
    for v in id_string:
        result = result + hex(ord(v)).lower()
    result = result[1:]
    # 查codes
    for key, value in codes.items():
        if key in result:
            result = value
            break

    return result


if __name__ == '__main__':
    # url = 'https://www.iesdouyin.com/share/user/105058236252'
    # url = 'https://www.iesdouyin.com/share/user/24058267831'
    url = 'https://www.iesdouyin.com/share/user/58758366245'
    # proxy_test1 = proxy_test(type='chrome')
    proxy_test1 = proxy_test(type='firefox')
    try:
        proxy_test1.main(url)

        print("1111")
        # proxy_test1.open_url(url)

        # init firefox
        # proxy_test1._init_firefox()
    finally:
        print("finally")
        # proxy_test1.quit()

    # a = spider_info('你哈')
    # print(json.dumps(a.__dict__, ensure_ascii=False))
